import type {
  AxiosError,
  AxiosInstance,
  AxiosProgressEvent,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios'
import type { MyRequestConfig } from './helpers'
import { errorCode } from '@/common/constants/errorCode'
import { closeLoading, openLoading } from '@/common/utils/globalLoading'
import { useUserStoreWithOut } from '@/store/modules/user'
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { set } from 'lodash-es'
import qs from 'qs'
import { ContentType } from './helpers'

const baseURL
  = window.baseConfig.BaseUrl
  || (import.meta.env.DEV
    ? import.meta.env.VITE_APP_BASE_API_PROXY
    : import.meta.env.VITE_APP_BASE_API)

const abortControllerMap: Map<string, AbortController> = new Map()

const axiosInstance: AxiosInstance = axios.create({
  baseURL,
  timeout: 60 * 1000,
})

axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  const controller = new AbortController()
  const url = config.url || ''
  config.signal = controller.signal
  abortControllerMap.set(url, controller)
  configureHeaders(config)
  configureQs(config)
  configureBlob(config)
  openLoading()
  return config
})

axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    const url = response.config.url || ''
    abortControllerMap.delete(url)
    closeLoading()
    // 如果后端的401等报错返回的status为200，而是在responseData中返回了相应的报错code，那么这里就需要额外处理错误
    // 如果不存在上述情况，下面代码可注释掉
    // #region 相关处理 ********************************************************************************
    const errorMessage
      = (response.data as any)?.msg
      || (response.data as any)?.message
      || errorCode.default
    if (response.data.code) {
      switch (response.data.code) {
        case 200:
          return response
        case 404:
          ElMessage.error(errorCode['404'])
          break
        case 403:
          ElMessage.error(errorCode['403'])
          break
        case 500:
          ElMessage.error(errorMessage)
          break
        case 401:
          ElMessage.error({
            message: errorCode['401'],
            onClose: () => {
              // TODO 清除缓存并跳转到重新登录页面
            },
          })
          break
      }
    }
    // #endregion *************************************************************************************
    return response
  },
  (error: AxiosError) => {
    closeLoading()
    if (error.response) {
      const errorMessage
        = (error.response.data as any)?.msg
        || (error.response.data as any)?.message
        || errorCode.default
      switch (error.response.status) {
        case 404:
          ElMessage.error(errorCode['404'])
          break
        case 403:
          ElMessage.error(errorCode['403'])
          break
        case 400:
          ElMessage.error(errorCode['400'])
          break
        case 401:
          ElMessage.error({
            message: errorCode['401'],
            onClose: () => {
              // TODO 清除缓存并跳转到重新登录页面
            },
          })
          break
        default:
          ElMessage.error(errorMessage)
          break
      }
    }
    return Promise.reject(error)
  },
)

const service = {
  request: <T = any>(config: MyRequestConfig) => {
    return axiosInstance.request<T>(config)
  },
  cancelRequest: (url: string | string[]) => {
    const urlList = Array.isArray(url) ? url : [url]
    for (const _url of urlList) {
      abortControllerMap.get(_url)?.abort()
      abortControllerMap.delete(_url)
    }
  },
  cancelAllRequest() {
    for (const [_, controller] of abortControllerMap) controller.abort()

    abortControllerMap.clear()
  },
}

// 配置headers
function configureHeaders(config: AxiosRequestConfig) {
  if (!config.headers?.['Content-Type'])
    set(config, ['headers', 'Content-Type'], ContentType.JSON)
  const userStore = useUserStoreWithOut()
  if (userStore.getToken)
    set(config, 'headers.Authorization', userStore.getToken)
}

// 配置 GET 请求传参
function configureQs(config: AxiosRequestConfig) {
  if (config.method?.toLowerCase() === 'get') {
    config.paramsSerializer = params =>
      qs.stringify(params, { arrayFormat: 'repeat' })
  }

  if (
    config.headers?.['Content-Type'] === ContentType.FORM_URLENCODED
    && typeof config.data !== 'string'
  ) {
    config.data = qs.stringify(config.data)
  }
}

// 处理blob下载进度
function configureBlob(config: AxiosRequestConfig) {
  if (config.responseType === 'blob' && !config.onDownloadProgress) {
    config.onDownloadProgress = function (progressEvent: AxiosProgressEvent) {
      const { loaded, total } = progressEvent
      if (total && loaded) {
        const percent = Math.round((loaded / total) * 100)
        console.log(`Downloading progress: ${percent}%`)
        return new Promise(resolve => setTimeout(resolve, 100)) // 每 100 毫秒更新一次下载进度
      }
    }
  }
}

export { axiosInstance, baseURL, service, service as default }
